package com.tongshu.miaosha.controller;

import com.tongshu.miaosha.Access.AccessLimit;
import com.tongshu.miaosha.domain.MiaoshaOrder;
import com.tongshu.miaosha.domain.MiaoshaUser;
import com.tongshu.miaosha.domain.OrderInfo;
import com.tongshu.miaosha.rabbitmq.MQSender;
import com.tongshu.miaosha.rabbitmq.MiaoshaMessage;
import com.tongshu.miaosha.redis.GoodsKey;
import com.tongshu.miaosha.redis.MiaoshaKey;
import com.tongshu.miaosha.result.CodeMsg;
import com.tongshu.miaosha.result.Result;
import com.tongshu.miaosha.service.GoodsService;
import com.tongshu.miaosha.service.MiaoshaService;
import com.tongshu.miaosha.service.MiaoshaUserService;
import com.tongshu.miaosha.service.OrderService;
import com.tongshu.miaosha.utils.MD5Util;
import com.tongshu.miaosha.utils.RedisUtil;
import com.tongshu.miaosha.utils.UUIDUtil;
import com.tongshu.miaosha.vo.GoodsVo;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/miaosha")
public class MiaoshaController implements InitializingBean {
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private MiaoshaService miaoshaService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private MQSender sender;


    private Map<Long, Boolean> localOverMap = new HashMap<>();

    /**
     * 用于系统初始化将库存存入Redis中
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> goodsVos = goodsService.listGoodsVo();
        if (goodsVos == null)
            return;
        for (GoodsVo goodsVo : goodsVos) {
            localOverMap.put(goodsVo.getId(), false);
            redisUtil.set(GoodsKey.getMiaoshaGoodsStock, "" + goodsVo.getId(), goodsVo.getStockCount());
        }

    }

    @PostMapping("/{path}/do_miaosha")
    @ResponseBody
    public Result<Integer> miaosha(Model model, MiaoshaUser user,
                                   @RequestParam("goodsId")long goodsId,
                                   @PathVariable("path")String path) {
        if (user == null)
            return Result.error(CodeMsg.SESSION_ERROR);

        // 验证path
        boolean checkPath = miaoshaService.checkPath(user, goodsId, path);
        if (!checkPath) {
            return Result.error(CodeMsg.REQUEST_ILLEGAL);
        }

        // 内存标记，减少redis访问
        Boolean over = localOverMap.get(goodsId);
        if (over) {
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }

        // 1. Redis预减库存，返回的为库存减一后的库存数量
        Long stock = redisUtil.decr(GoodsKey.getMiaoshaGoodsStock, "" + goodsId);
        if (stock < 0) {
            // 如果库存不足，置该商品内存标记为true，即库存不足
            localOverMap.put(goodsId, true);
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }

        // 2. 判断是否重复秒杀
        MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
        if (order != null)
            return Result.error(CodeMsg.REPEATE_MIAO_SHA);

        // 入队
        MiaoshaMessage message = new MiaoshaMessage();
        message.setUser(user);
        message.setGoodsId(goodsId);
        sender.sendMiaoshaMessage(message);
        return Result.success(0); // 排队中

//        // 判断库存
//        GoodsVo goodsVo = goodsService.getGoodsVoByGoodsId(goodsId);
//        Integer stockCount = goodsVo.getStockCount();
//        if (stockCount <= 0) {
//            return Result.error(CodeMsg.MIAO_SHA_OVER);
//        }
//        // 判断是否重复秒杀
//        MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
//        if (order != null) {
//            return Result.error(CodeMsg.REPEATE_MIAO_SHA);
//        }
//
//        // 减库存 下订单 写入秒杀订单
//        OrderInfo orderInfo = miaoshaService.miaosha(user, goodsVo);
//
//        return Result.success(orderInfo);

    }

    /**
     *
     * @param model
     * @param user
     * @param goodsId
     * @return orderId：秒杀成功
     *          -1：秒杀失败
     *          0：仍在排队中
     */
    @GetMapping("/result")
    @ResponseBody
    public Result<Long> miaoshaResult(Model model, MiaoshaUser user,
                                      @RequestParam("goodsId")long goodsId) {
        model.addAttribute("user", user);
        if (user == null) {
            return Result.error(CodeMsg.SESSION_ERROR);
        }
        long result = miaoshaService.getMiaoshaResult(user.getId(), goodsId);
        return Result.success(result);
    }

    @AccessLimit(seconds = 5, maxCount = 5)
    @GetMapping("/path")
    @ResponseBody
    public Result<String> getMiaoshaPath(MiaoshaUser user,
                                         @RequestParam("goodsId")long goodsId,
                                         @RequestParam(value = "verifyCode", defaultValue = "0") int verifyCode) {
        if (user == null)
            return Result.error(CodeMsg.SESSION_ERROR);

        // 验证码校验
        boolean check = miaoshaService.checkVerifyCode(user, goodsId, verifyCode);
        if (!check) {
            return Result.error(CodeMsg.REQUEST_ILLEGAL);
        }

        String path = miaoshaService.createMiaoshaPath(user, goodsId);
        return Result.success(path);
    }

    // 生成图片验证码
    @GetMapping("/verifyCode")
    @ResponseBody
    public Result<String> getMiaoshaVerifyCode(HttpServletResponse response, MiaoshaUser user,
                                               @RequestParam("goodsId")long goodsId) {
        if (user == null) {
            return Result.error(CodeMsg.SESSION_ERROR);
        }

        try {
            BufferedImage image = miaoshaService.createVerifyCode(user, goodsId);
            OutputStream out = response.getOutputStream();
            ImageIO.write(image, "JPEG", out);
            out.flush();
            out.close();
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(CodeMsg.SERVER_ERROR);
        }
    }
}
